﻿using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace System
{
    public class WebRequester
    {
        public static System.Threading.ManualResetEvent bgProcessing = new System.Threading.ManualResetEvent(false);
        const int DefaultTimeout = 150000; // 2.5 minutes timeout
        
        internal static Stream getUriSync(Uri url)
        {
            if (!url.IsAbsoluteUri)
            {
                try
                {
                    var uri = url.OriginalString;
                    // local resource
                    return Application.GetResourceStream(
                            url).Stream;
                }
                catch(Exception ex) { }
            }

            Stream istr = null;
            HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
            wr.UseDefaultCredentials = true;

            IAsyncResult iAsyncResult = wr.BeginGetResponse(new AsyncCallback((result) =>
            {
                WebResponse response = wr.EndGetResponse(result);
                istr = response.GetResponseStream();

                bgProcessing.Set();
            }), null);

            System.Threading.ThreadPool.RegisterWaitForSingleObject(iAsyncResult.AsyncWaitHandle, new System.Threading.WaitOrTimerCallback(WebRequestTimeout), wr, DefaultTimeout, true);
            bgProcessing.WaitOne();
            return istr;
        }
        public static Stream postUriSync(Uri url, byte[] array, string contentType = "", string acceptString = "", string userName="", string password="",  bool getEncoding=false )
        {
            LastEncoding = "";
            HttpWebRequest con = (HttpWebRequest)WebRequest.Create(url);
#if !WINDOWS_PHONE
            con.ContentLength = array.Length;
#endif
            if(! String.IsNullOrEmpty(contentType))
                con.ContentType = contentType;
            if(! String.IsNullOrEmpty(acceptString))
                con.Accept = acceptString;
            con.Method = "POST";
            if (!String.IsNullOrEmpty(userName))
            {
                string authInfo = userName + ":" + password;
                authInfo = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(authInfo));
                con.Headers["Authorization"] = "Basic " + authInfo;
            }

            Stream reqStream = null; 
            
            IAsyncResult iAsyncResult = con.BeginGetRequestStream(new AsyncCallback((result) =>
            {
                reqStream = con.EndGetRequestStream(result);
                bgProcessing.Set();
            }), null);

            System.Threading.ThreadPool.RegisterWaitForSingleObject(iAsyncResult.AsyncWaitHandle, new System.Threading.WaitOrTimerCallback(WebRequestTimeout), con, DefaultTimeout, true);
            bgProcessing.WaitOne();

            if(reqStream == null)
                throw new IOException("error getting request stream");

            reqStream.Write(array, 0, array.Length);
            reqStream.Close();
            
            HttpWebResponse response = null;

            iAsyncResult = con.BeginGetResponse(new AsyncCallback((result) =>
            {
                response = (HttpWebResponse)con.EndGetResponse(result);
                bgProcessing.Set();
            }), null);

            System.Threading.ThreadPool.RegisterWaitForSingleObject(iAsyncResult.AsyncWaitHandle, new System.Threading.WaitOrTimerCallback(WebRequestTimeout), con, DefaultTimeout, true);
            bgProcessing.WaitOne();

            if (response == null)
                throw new IOException("error getting response stream");

            if (response.StatusCode != HttpStatusCode.OK)
                throw new IOException("invalid http response: " + (int)response.StatusCode);
            var inp = response.GetResponseStream();
            MemoryStream strmResult = new MemoryStream();
            try
            {
                var buffer = new Byte[4 * 1024 * 1024];// 4mb
                var read = inp.Read(buffer, 0, buffer.Length);
                while (read > 0)
                {
                    strmResult.Write(buffer, 0, read);
                    read = inp.Read(buffer, 0, buffer.Length);
                }
                strmResult.Flush();
                strmResult.Position = 0;
                if (getEncoding)
                    LastEncoding = (String)response.Headers["ContentEncoding"];
            }
            finally
            {
                inp.Close();
                response.Close();
            }
            return strmResult;


        }

        public static String LastEncoding{get;set;}
        // Abort the request if the timer fires.
        private static void WebRequestTimeout(object state, bool timedOut)
        {
            if (timedOut)
            {
                HttpWebRequest req = state as HttpWebRequest;
                if (req != null)
                {
                    req.Abort();
                }
            }
        }

    }
}
